package com.ruoyi.common.utils.distance;

import org.apache.commons.lang3.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class DistanceUtils
{

    // 地球半径（千米）
    private static final BigDecimal EARTH_RADIUS = BigDecimal.valueOf(6371);
    // 精度设置
    private static final int SCALE = 8;
    private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;

    /**
     * 计算两个经纬度点之间的距离（单位：千米）
     * @param lat1 第一个点的纬度
     * @param lng1 第一个点的经度
     * @param lat2 第二个点的纬度
     * @param lng2 第二个点的经度
     * @return 距离（千米），保留两位小数
     */
    public static BigDecimal calculateDistance(BigDecimal lat1, BigDecimal lng1,
                                               BigDecimal lat2, BigDecimal lng2) {
        // 将角度转换为弧度 (π/180)
        BigDecimal radianFactor = BigDecimal.valueOf(Math.PI).divide(BigDecimal.valueOf(180), SCALE, ROUNDING_MODE);

        BigDecimal lat1Rad = lat1.multiply(radianFactor);
        BigDecimal lng1Rad = lng1.multiply(radianFactor);
        BigDecimal lat2Rad = lat2.multiply(radianFactor);
        BigDecimal lng2Rad = lng2.multiply(radianFactor);

        // 计算纬度差和经度差
        BigDecimal latDiff = lat2Rad.subtract(lat1Rad);
        BigDecimal lngDiff = lng2Rad.subtract(lng1Rad);

        // Haversine公式实现
        // a = sin²(Δlat/2) + cos(lat1) * cos(lat2) * sin²(Δlng/2)
        BigDecimal sinLatDiffHalf = BigDecimal.valueOf(Math.sin(latDiff.divide(BigDecimal.valueOf(2), SCALE, ROUNDING_MODE).doubleValue()));
        BigDecimal sinLngDiffHalf = BigDecimal.valueOf(Math.sin(lngDiff.divide(BigDecimal.valueOf(2), SCALE, ROUNDING_MODE).doubleValue()));

        BigDecimal a = sinLatDiffHalf.pow(2)
                .add(
                        BigDecimal.valueOf(Math.cos(lat1Rad.doubleValue()))
                                .multiply(BigDecimal.valueOf(Math.cos(lat2Rad.doubleValue())))
                                .multiply(sinLngDiffHalf.pow(2))
                );

        // c = 2 * asin(√a)
        BigDecimal c = BigDecimal.valueOf(2)
                .multiply(BigDecimal.valueOf(Math.asin(Math.sqrt(a.doubleValue()))));

        // 计算距离:保留0位小数
        return EARTH_RADIUS.multiply(c).setScale(0, ROUNDING_MODE);
    }


    public static boolean isNullOrZero(BigDecimal value) {
        return ObjectUtils.isEmpty(value) || BigDecimal.ZERO.compareTo(value) == 0;
    }

}
